package com.sky.filter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private static Map<RequestMatcher, List<ConfigAttribute>> configAttributeMap = null;

    @Autowired
    private DynamicSecurityService dynamicSecurityService;

    /**
     * 提供清除方法
     * 在资源分配的时候就清除掉
     */
    public void clearDataSource() {
        configAttributeMap.clear();
        configAttributeMap = null;
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {

        // 在清除后就会再次获取最新的资源角色信息
        if (CollectionUtils.isEmpty(configAttributeMap)) {
            this.loadDataSource();
        }

        ArrayList<ConfigAttribute> configAttributes = new ArrayList<>();

        // 获取当前的访问路径
        HttpServletRequest request = ((FilterInvocation) object).getRequest();

        // 循环所有资源角色信息
        for (RequestMatcher pattern : configAttributeMap.keySet()) {
            // 匹配路径
            if (pattern.matches(request)) {
                // 获取当前路径对应的所有角色信息
                configAttributes.addAll(configAttributeMap.get(pattern));
            }
        }

        return configAttributes;
    }

    /**
     * @PostConstruct Spring在创建bean的时候调用这个注解初始化方法
     * 读取到所有的资源角色信息
     */
    @PostConstruct
    private void loadDataSource() {
        configAttributeMap = dynamicSecurityService.loadDataSource();
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return Collections.emptyList();
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}
